/**************************
 * Project: ePoverty
 * Filename: PieChart.java
 * Description: Simple percentage pie chart.
 * Name: Bunna Veth
 * Date: Apr 9, 2012
 **************************/
package epoverty;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RadialGradientPaint;
import java.awt.geom.Point2D;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class PieChart extends JPanel
{
    //Settings
    private Font TITLE_FONT = new Font("Arial", Font.BOLD, 16);
    private Font TEXT_FONT = new Font("Arial", Font.PLAIN, 12);
    private Color TEXT_COLOR = Color.WHITE;
    private Color BACKGROUND_COLOR = Color.BLACK;
    private Color[] COLORS = {Color.GREEN, Color.WHITE, new Color(200,200,200), new Color(150,150,150), new Color(100,100,100), new Color(50,50,50)};
    private Color GRADIENT_START = new Color(0,0,0,0);
    private Color GRADIENT_END = new Color(0,0,0,50);
    private int START_ANGLE = 30; //angle the first slice is drawn from (0-360)

    //Fields
    private String chartTitle;
    private Object[] categoryNames;
    private int[] degrees;
    private String[] percentages;
    private Object[] rawData;

    //Constructor *****************************************************
    public PieChart(String title, Object[] categories, Object[] data)
    {
        setBackground(BACKGROUND_COLOR);
        chartTitle = title;
        categoryNames = categories;
        rawData = data;

        normalizeData();
    }

    //Normalizes data to percentages of a full circle
    private void normalizeData()
    {
        percentages = new String[rawData.length];
        degrees = new int[rawData.length];
        double[] values = new double[rawData.length];
        double sumOfValues = 0;

        //convert to doubles and calculate sum
        for (int i = 0; i < rawData.length; i++)
        {
            values[i] = Double.parseDouble(rawData[i].toString());
            sumOfValues += values[i];
        }

        //convert to degrees
        int sumOfAngles = 0;
        for (int i = 0; i < values.length; i++)
        {
            percentages[i] = String.format("%.1f%%", 100 * values[i] / sumOfValues); //i.e. 25.6%

            if (i == values.length - 1)
                degrees[i] = 360 - sumOfAngles; //completes the full 360 to remove rounding error
            else
                degrees[i] = (int) (values[i] / sumOfValues * 360);

            sumOfAngles += degrees[i];
        }
    }

    //Draw Chart ***********************************************************
    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;

        //chart title
        g2d.setColor(TEXT_COLOR);
        g2d.setFont(TITLE_FONT);
        FontMetrics fontMeter = g.getFontMetrics();
        int titleX = (int) getHeight() + 5;
        int titleY = (int) fontMeter.getAscent();
        g2d.drawString(chartTitle, titleX, titleY);

        //pie settings
        int startAngle = START_ANGLE;
        int pieDiameter = getHeight();
        int keyPosition = titleY + 5;
        int keyOffset = 20;

        for (int i = 0; i < degrees.length; i++)
        {
            //pie slice
            g2d.setColor(COLORS[i % COLORS.length]); //cycle through colors if categories exceed color amount
            g2d.fillArc(0, 0, pieDiameter, pieDiameter, startAngle, degrees[i]);
            startAngle += degrees[i];

            //colored box
            int boxX = pieDiameter + 5;
            int boxY = keyPosition + 3;
            int boxWidth = 15;
            g2d.fillRect(boxX, boxY, boxWidth, boxWidth);

            //legend key
            g2d.setColor(TEXT_COLOR);
            g2d.setFont(TEXT_FONT);
            String keyText = String.format("%s (%s)", categoryNames[i], percentages[i]);
            int keyX = boxX + 20;
            int keyY = keyPosition + 15;
            g2d.drawString(keyText, keyX, keyY);

            keyPosition += keyOffset; //move key position
        }

        //gradient overlay
        Point2D gradientCenter = new Point2D.Float(pieDiameter/2.0f, pieDiameter/2.0f);
        float gradientRadius = pieDiameter - 20f;
        float[] colorDistribution = {0f,1f};
        Color[] gradientColors = {GRADIENT_START, GRADIENT_END};
        RadialGradientPaint gradient = new RadialGradientPaint(gradientCenter,gradientRadius,colorDistribution,gradientColors);
        g2d.setPaint(gradient);
        g2d.fillOval(10, 10, pieDiameter-20, pieDiameter-20);
    }
    
    //Public Setters ********************************************************************************
    public void setData(Object[] categories, Object[] data)
    {
        categoryNames = categories;
        rawData = data;
        normalizeData();
        repaint();
    }

    public void setChartColors(Color[] colors)
    {
        COLORS = colors;
        repaint();
    }

    public void setTextColor(Color c)
    {
        TEXT_COLOR = c;
        repaint();
    }

    //Test Method (delete before release) ********************************************
    public static void main(String[] args)
    {
        //Sample Usage
        Object[] categories = {"Overhead", "Charity", "Expeditions", "Processing Fees"};
        Object[] data = {2100, 5600, 12000, 700};
        PieChart chart = new PieChart("Money Distribution", categories, data);

        //Display on JFrame
        JFrame frame = new JFrame("Pie Chart");
        frame.add(chart);
        frame.setSize(450, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

}//end class